package com.jieshuibao.service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.jdom.JDOMException;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;

import com.jieshuibao.common.config.Const;
import com.jieshuibao.common.res.BaseRes;
import com.jieshuibao.mapper.UserExMapper;
import com.jieshuibao.mapper.WxUserMapper;
import com.jieshuibao.model.db.RedEnvelopes;
import com.jieshuibao.model.db.User;
import com.jieshuibao.model.db.Withdraw;
import com.jieshuibao.model.db.WxUser;
import com.jieshuibao.model.db.WxUserExample;
import com.jieshuibao.model.db.WxUserExample.Criteria;
import com.jieshuibao.model.domain.CookieUser;
import com.jieshuibao.service.WeiXinPayService.EnterpriseQueryTask;
import com.jieshuibao.util.DateUtils;
import com.jieshuibao.util.IdGen;
import com.jieshuibao.util.JsonUtil;
import com.jieshuibao.util.NetworkUtil;
import com.jieshuibao.util.PayTypeUtil;
import com.jieshuibao.util.StringUtils;
import com.jieshuibao.util.WithdrawUtil;
import com.jieshuibao.wx.util.PayCommonUtil;

@Service
public class WxUserService{
	String randomString = PayCommonUtil.getRandomString(32);
	private static final Logger logger = Logger
			.getLogger(WxUserService.class);
	
	@Resource
	private TaskExecutor taskExecutor;// 线程池 
	
	@Resource
	private WxUserMapper wxUserMapper;
	
	@Resource
	private UserService UserService;
	
	@Resource
	private RedisService redisService;
	
	@Resource
	private WithdrawService withdrawService;
	
	@Resource
	private RedEnvelopesService redEnvelopesService;
	
	@Resource
	private WeiXinPayService weiXinPayService;
	
	@Resource
	private UserExMapper userExMapper;
	
	public void addWxUser(WxUser wxUser) {
		wxUserMapper.insertSelective(wxUser);
	}
	
	public void delWxUserByOpenid(String openid) {
		wxUserMapper.deleteByPrimaryKey(openid);
	}
	
	public void updateWxUser(WxUser wxUser) {
		wxUserMapper.updateByPrimaryKeySelective(wxUser);
	}
	
	public WxUser getWxUserByOpenid(String openid) {
		return wxUserMapper.selectByPrimaryKey(openid);
	}
	
	public List<WxUser> getPageWxUser(WxUserExample wxUserExample) {
		return wxUserMapper.selectPage(wxUserExample);
	}
	
	public int countWxUser(WxUserExample wxUserExample) {
		return wxUserMapper.countByExample(wxUserExample);
	}
	
	public boolean countWxUserByUserId(String userId){
		WxUserExample wxUserExample = new WxUserExample();
		Criteria createCriteria = wxUserExample.createCriteria();
		createCriteria.andUserIdEqualTo(userId);
		createCriteria.andOpenidIsNotNull();
		int i = wxUserMapper.countByExample(wxUserExample);
		if (i>0) {
			return false;
		}else {
			return true;
		}
		
	}
	
	/**
	 * 和移动端做关联
	 * @param phnoe
	 * @param openId
	 */
	public Object  bingdingWxuser(String phone,String openId){
		BaseRes<User> baseRes = UserService.getWxUserByphone(phone);
		BaseRes<String> res = new BaseRes<String>();
		
		if (baseRes==null) {
			//新用户
			User user = new User();
			String uuid = IdGen.uuid();
			user.setPhoneNumber(uuid);
			user.setUuid(uuid);
			user.setPhone(phone);
			String replaceAll = phone.replaceAll("(\\d{3})\\d{4}(\\d{4})","$1****$2");
			user.setRealName(replaceAll);
			user.setRole(Const.USER_ROLE_1);
			user.setBalance(0.0);
			user.setRegisterDate(new Date());
			WxUser wxUser = new WxUser();
			wxUser.setOpenid(openId);
			wxUser.setUserId(uuid);
			UserService.addUser(user);
			wxUserMapper.updateByPrimaryKeySelective(wxUser);
			res.setCode(BaseRes.SUCCESS_CODE);
			res.setDes(BaseRes.SUCCESS_DES);
			res.setData("1");//是新用户 需要绑问答卡
			redisService.set("wx_"+uuid+"_BINDING", uuid, 12*60*60);//绑卡时用来判断是不是新用户
			RedEnvelopes redEnvelopes = new RedEnvelopes();
			redEnvelopes.setMoney(PayTypeUtil.REDENVELOPES_REGISTER_QAMONEY);//金额
			redEnvelopes.setUserPhoneNum(uuid);//领取红包的用户的用户主键
			redEnvelopes.setRedType(PayTypeUtil.REDENVELPES_REGISTER_QACARD);//红包类型
			//增加红包记录且用户问答卡余额增加
			redEnvelopesService.addQACardRedEnvelopes(redEnvelopes,null);
			return res;
		}else {
			String code2 = baseRes.getCode();
			if (code2.equals(BaseRes.SUCCESS_CODE)) {
				User data = baseRes.getData();
				String userId = data.getPhoneNumber();
				boolean b = this.countWxUserByUserId(userId);
				if (b) {
					WxUser wxUser2 = new WxUser();
					wxUser2.setOpenid(openId);
					wxUser2.setUserId(userId);
					wxUserMapper.updateByPrimaryKeySelective(wxUser2);
					res.setCode(BaseRes.SUCCESS_CODE);
					res.setDes(BaseRes.SUCCESS_DES);
					res.setData("2");//是老用户 不需要绑问答卡
					return res;
				}else {
					res.setCode(BaseRes.FAIL_CODE);
					res.setDes("此手机号已被其他微信绑定！");
					res.setData("2");//是老用户 不需要绑问答卡
					return res;
				}
				
			}else {
				return baseRes;
			}
		}
	}
	
	//微信公众号用户提现
	
	public BaseRes<String> wxUserWithdraw(CookieUser cookieUser,double money,String openId,HttpServletRequest request){
		BaseRes<String> res = new BaseRes<String>();
		if (cookieUser==null||StringUtils.isBlank(openId)||money<=0) {
			//参数错误
			res.setCode(BaseRes.ERRORPARAM_CODE);
			res.setDes("参数错误！");
			return res;
		}
		double balance = cookieUser.getBalance();
		if(!WithdrawUtil.isAgree(money)){
			res.setCode(BaseRes.ERRORPARAM_CODE);
			res.setDes("最低提现金额为20元哦！");
			return res;
		}
		if (money>balance) {
			res.setCode(BaseRes.FAIL_CODE);
			res.setDes("余额不足！");
			return res;
			
		}
		String phoneNumber = cookieUser.getPhoneNumber();
		String uuid = IdGen.uuid();

		try {
			if(!isWithDraw(phoneNumber)){
				List<Withdraw> lastRecord = withdrawService.getLastRecord(phoneNumber);
				Withdraw withdraw = lastRecord.get(0);
				Date createDate = withdraw.getCreateDate();
				String formatDate = DateUtils.formatDate(createDate, "yyyy-MM-dd");
				res.setCode(BaseRes.FAIL_CODE);
				res.setDes("两次提现间隔时间须大于"+Const.TIME+"天,您上次提现时间为"+formatDate);
				return res;
			}
			
			String remoteAddr = NetworkUtil.getIpAddress(request).equals("0:0:0:0:0:0:0:1")?"127.0.0.1":NetworkUtil.getIpAddress(request);
			boolean b = updateUserWithdraw(cookieUser, money, uuid, remoteAddr, openId,"0");
			if (!b) {
				res.setCode(BaseRes.FAIL_CODE);
				res.setDes("网络抖动！联系管理员");
				return res;
			}
			if(money <= Const.CHECKMONEY){    //提现金额小于等于审核限制金额是直接到账
				String desc = "航信办税宝微信提现";
				BigDecimal totalAmount = new BigDecimal( money);
				SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();
				parameterMap.put("mch_appid", PayCommonUtil.MXPUBLIC_APPID);
				parameterMap.put("mchid", PayCommonUtil.MCH_ID);
				parameterMap.put("nonce_str", randomString);
				parameterMap.put("partner_trade_no", uuid);
				parameterMap.put("openid", openId);
				BigDecimal total = totalAmount.multiply(new BigDecimal(100));
				java.text.DecimalFormat df = new java.text.DecimalFormat("0");
				parameterMap.put("amount", df.format(total));
//			parameterMap.put("check_name", "NO_CHECK");
				parameterMap.put("check_name", "FORCE_CHECK");
				parameterMap.put("re_user_name", cookieUser.getUserName());
				parameterMap.put("desc", desc);
				parameterMap.put("spbill_create_ip","60.205.84.1");
				
				String sign = PayCommonUtil.createSign("UTF-8", parameterMap);
				parameterMap.put("sign", sign);
				
				String requestXML = PayCommonUtil.getRequestXml(parameterMap);
				logger.info("微信企业支付请求报文：" + requestXML);
				String result = PayCommonUtil.httpsRequestEnterprise(PayCommonUtil.ENTERPRISE_PAY_URL, requestXML);
				logger.info("企业支付返回报文："+result);
				Map<String,String> map = PayCommonUtil.doXMLParse(result);
				String return_code = map.get("return_code");
				String result_code = map.get("result_code");
				String partner_trade_no = map.get("partner_trade_no");
				String payment_no = map.get("payment_no");
				String payment_time = map.get("payment_time");
				
				if (return_code.equalsIgnoreCase(PayCommonUtil.SUCCESS)) {
					if (result_code.equalsIgnoreCase(PayCommonUtil.SUCCESS)) { 
						//修改提现表状态
						Withdraw withdraw = new Withdraw();
						withdraw.setUuid(partner_trade_no);
						withdraw.setWxid(payment_no);
						withdraw.setSucDate(DateUtils.parseDate(payment_time));
						withdraw.setStatus(PayCommonUtil.PAYSUCCESS_STATUS);
						withdrawService.updateWithdraw(withdraw);
						res.setCode(BaseRes.SUCCESS_CODE);
						res.setDes("提现成功");
						logger.warn("修改体现表状态");
						
						return res;
					}else{
						String err_code = map.get("err_code");
						String err_code_des = map.get("err_code_des");
						Withdraw withdraw = new Withdraw();
						withdraw.setUuid(uuid);
						withdraw.setErrorCode(err_code);
						withdraw.setReason(err_code_des);
						withdrawService.updateWithdraw(withdraw);  //保存微信返回错误信息
						logger.warn("保存微信返回错误信息："+JsonUtil.toJson(withdraw));
						updateUserWithdraw(cookieUser, money, uuid, remoteAddr, openId,"1");
						logger.warn("调用微信企业支付：err_code"+err_code+",err_code_des"+err_code_des);
						if(err_code.equalsIgnoreCase("NAME_MISMATCH")){
							res.setCode(BaseRes.FAIL_CODE);
							res.setDes("姓名请与微信实名保持一致");
							return res;
						}
						res.setCode(BaseRes.FAIL_CODE);
						res.setDes("提现失败，请联系管理员");
						return res;
					}
				}else {
					Withdraw withdraw = new Withdraw();
					withdraw.setUuid(partner_trade_no);
					withdraw.setStatus(PayCommonUtil.PENDING_QUERY_CODE);
					withdraw.setReason("网络错误，待查询");
					withdrawService.updateWithdraw(withdraw);  //记录网络错误后的待查询状态
					//TODO  可能网络出现错误，查询支付结果    线程池中查询支付结果
					this.taskExecutor.execute(new EnterpriseQueryTask(partner_trade_no));  
					res.setCode(BaseRes.FAIL_CODE);
					res.setDes("系统繁忙");
					logger.error("调用微信企业付款通信异常");
					return res;
				}
			}else{
				res.setCode(BaseRes.SUCCESS_CODE);
				res.setDes("您的提现申请已提交，预计2个工作日内到账");
				return res;
			}
		}catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			updateUserWithdraw(cookieUser, money, uuid, null, openId,"1");
			logger.warn("调用微信企业支付：,err_code_des"+e);
			res.setCode(PayCommonUtil.FAIL_CODE);
			res.setDes("提现失败，请联系管理员");
			return res;
		}
		
	}
	class EnterpriseQueryTask implements Runnable{
		String partner_trade_no;
		int n;
		public EnterpriseQueryTask(String partner_trade_no){
			this.partner_trade_no = partner_trade_no;
		}
		@Override
		public void run() {
			if(n>=3){
				weiXinPayService.enterpriseOrder(partner_trade_no);
				n++;
			}
		}
		
	}
	/**
	 * 两次提现间隔是否大于限制时间
	 * @param phone
	 * @return
	 */
	private boolean isWithDraw(String phone){
		List<Withdraw> lastRecord = withdrawService.getLastRecord(phone);
		if(null!=lastRecord&&lastRecord.size()>0){
			Withdraw withdraw = lastRecord.get(0);
			Date createDate = withdraw.getCreateDate();
			logger.warn("上次提现时间："+DateUtils.formatDateTime(createDate));
			long pastDays = DateUtils.pastDays(createDate);
			logger.warn("过去天数："+pastDays);
			if(pastDays > Const.TIME){
				return true;
			}
			return false;
		}
		return true;
	}
	/**
	 * 处理提现业务
	 * @param userId 用户id 
	 * @param money 金额
	 * @param pId 业务id
	 * @param ip ip地址
	 * @param openId 微信openid
	 * @param type 类型 0 发起提现 1 提现异常退回
	 */
	private boolean updateUserWithdraw(CookieUser cookieUser,double money,String pId,String ip,String openId,String type){
		try {
			if (cookieUser==null) {
				return false;
			}
			String userId = cookieUser.getPhoneNumber();
			String userName = cookieUser.getUserName();
			double balance = cookieUser.getBalance();
			
			if (StringUtils.isNotBlank(type)&&StringUtils.isNotBlank(userId)&&StringUtils.isNotBlank(pId)) {
				User u = new User();
				u.setPhoneNumber(userId);
				Withdraw withdraw = new Withdraw();
				withdraw.setUuid(pId);
				if (type.equals("0")) {
					if (balance<money) {
						return false;
					}
					
					u.setBalance(-money);
					logger.warn("提现减去用户余额："+JsonUtil.toJson(u));
					userExMapper.updateUserAdvisoryNum(u);
					//生成提现流水
					
					withdraw.setCreateDate(new Date());
					withdraw.setMoney(money);
					withdraw.setName(userName);
					withdraw.setOpenid(openId);
					withdraw.setPhoneNum(userId);
					withdraw.setStatus(PayCommonUtil.PAYPENDING_STATUS);
					withdraw.setAccountType("wp");
					withdraw.setIp(ip);
					withdrawService.addWithdraw(withdraw);
					return true;
				}else  if (type.equals("1")) {
					u.setBalance(money);
					withdraw.setStatus(PayCommonUtil.ALREADY_REFUND_CODE);
					logger.warn("记录退回操作："+JsonUtil.toJson(withdraw));
					withdrawService.updateWithdraw(withdraw);
					logger.warn("提现失败退回余额："+JsonUtil.toJson(u));
					userExMapper.updateUserAdvisoryNum(u);
					return true;
				}else {
					return false;
				}
				
			}else {
				return false;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			logger.warn("提现操作业务表异常：");
			return false;
		}
	} 
}
